package com.jacobson.core.mvp

import android.content.Context
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.annotation.LayoutRes
import androidx.recyclerview.widget.RecyclerView
import com.jacobson.core.framework.delegation.WeakRef
import com.jacobson.core.widget.logger.LoggerFactory
import com.jacobson.core.widget.rv.DraggableAdapter
import java.util.*
import java.util.concurrent.atomic.AtomicInteger


/**
 * ================================================
 *
 *  @author Wucz on 2018/7/24 9:28
 * ================================================
 */

abstract class ListRecyclerAdapter<T>(
        context: Context
) : RecyclerView.Adapter<ListRecyclerAdapter.ViewHolder<T>>(), DraggableAdapter {
    private val logger = LoggerFactory.getLogger()
    protected val context by WeakRef { context }
    private val dataList: MutableList<T> = arrayListOf()
    private val nextPage: AtomicInteger = AtomicInteger(1)

    fun hasMoreData(count: Int): Boolean {
        return dataList.size < count
    }

    /**
     * 下一分页
     */
    fun nextPage() = nextPage.get()

    /**
     * 分页列表
     */
    fun page(page: Int, dataList: List<T>) {
        if (page == nextPage.get()) {
            this.dataList.addAll(dataList)
            nextPage.incrementAndGet()
            notifyDataSetChanged()
        }
    }

    /**
     * 更新列表
     */
    fun update(dataList: List<T>?) {
        this.dataList.clear()
        nextPage.set(2)
        dataList?.takeIf { it.isNotEmpty() }?.let {
            this.dataList.addAll(it)
        }
        notifyDataSetChanged()
    }

    /**
     * 添加多个
     */
    fun addAll(dataList: List<T>, index: Int = -1) {
        val position = usualPosition(index)
        if (position < 0) {
            this.dataList.addAll(dataList)
        } else {
            this.dataList.addAll(position, dataList)
        }
        notifyDataSetChanged()
    }

    /**
     * 添加单个
     */
    fun add(data: T, index: Int = -1) {
        val position = usualPosition(index)
        if (position < 0) {
            this.dataList.add(data)
            notifyItemInserted(usualPosition(dataList.size - 1, true))
        } else {
            this.dataList.add(position, data)
            notifyItemInserted(usualPosition(position, true))
        }
        notifyDataSetChanged()
    }

    fun remove(position: Int) {
        val index = usualPosition(position)
        if (index in 0 until dataList.size) {
            dataList.removeAt(index)
            notifyItemRemoved(position)
            if (index != dataList.size) {
                notifyItemRangeChanged(position, itemCount - position)
            } else {
                notifyDataSetChanged()
            }
        }
    }

    fun getDataList(): List<T> = dataList

    fun onDestroy() {
        this.dataList.clear()
    }

    override fun onDragSwap(sourcePosition: Int, targetPosition: Int): Boolean {
        if (sourcePosition < targetPosition) {
            for (position in sourcePosition until targetPosition) {
                Collections.swap(dataList, position, position + 1)
            }
        } else {
            for (position in sourcePosition downTo targetPosition + 1) {
                Collections.swap(dataList, position, position - 1)
            }
        }
        return true
    }

    override fun onDragRemove(position: Int): Boolean {
        if (dataList.size > position && position >= 0) {
            dataList.removeAt(position)
            return true
        }
        return false
    }

    override fun getItemCount(): Int = dataList.size

    override fun onBindViewHolder(holder: ViewHolder<T>, position: Int) {
        if (!isUnusualPosition(position)) {
            val index = usualPosition(position)
            dataList[index]?.run {
                holder.itemView.setOnClickListener { listener?.onItemClick(dataList, this, position) }
                holder.onBindView(dataList, this, position)
            }
        } else {
            holder.itemView.setOnClickListener { onUnusualClickListener?.onUnusualClick(dataList, position) }
            holder.onUnusualBindView(dataList, position)
        }
    }

    override fun onBindViewHolder(holder: ViewHolder<T>, position: Int, payloads: MutableList<Any>) {
        if (payloads.isEmpty()) {
            super.onBindViewHolder(holder, position, payloads)
            return
        }
        if (!isUnusualPosition(position)) {
            val index = usualPosition(position)
            dataList[index]?.run {
                holder.itemView.setOnClickListener { listener?.onItemClick(dataList, this, position) }
                holder.onBindView(dataList, this, position, payloads)
            }
        } else {
            holder.itemView.setOnClickListener { onUnusualClickListener?.onUnusualClick(dataList, position) }
            holder.onUnusualBindView(dataList, position, payloads)
        }
    }

    protected open fun isUnusualPosition(position: Int): Boolean = position >= dataList.size

    protected open fun usualPosition(position: Int, reverse: Boolean = false): Int = position

    abstract class ViewHolder<T>(
            context: Context,
            parent: ViewGroup,
            @LayoutRes itemResId: Int) : RecyclerView.ViewHolder(
            LayoutInflater.from(context).inflate(itemResId, parent, false)
    ) {
        protected val context by WeakRef { context }
        abstract fun onBindView(dataList: List<T>, data: T, position: Int)
        open fun onBindView(dataList: List<T>, data: T, position: Int, payloads: MutableList<Any>) = Unit
        open fun onUnusualBindView(dataList: MutableList<T>, position: Int) = Unit
        open fun onUnusualBindView(dataList: MutableList<T>, position: Int, payloads: MutableList<Any>) = Unit
    }

    private var listener: OnItemClickListener<T>? = null
    private var onUnusualClickListener: OnUnusualClickListener<T>? = null
    fun setOnItemClickListener(listener: OnItemClickListener<T>) {
        this.listener = listener
    }

    fun setOnUnusualClickListener(listener: OnUnusualClickListener<T>) {
        this.onUnusualClickListener = listener
    }

    interface OnItemClickListener<T> {
        fun onItemClick(dataList: List<T>, data: T, position: Int)
    }

    interface OnUnusualClickListener<T> {
        fun onUnusualClick(dataList: List<T>, position: Int)
    }
}